import { Router } from 'express'
import { body, validationResult } from 'express-validator'
import { supabase } from '../server'
import { logger } from '../utils/logger'
import { asyncHandler, createError } from '../middleware/errorHandler'
import { AuthenticatedRequest, logUserActivity } from '../middleware/auth'

const router = Router()

// Helper function to check validation results
const checkValidation = (req: any, res: any) => {
  const errors = validationResult(req)
  if (!errors.isEmpty()) {
    return res.status(400).json({
      success: false,
      message: 'Validation failed',
      errors: errors.array()
    })
  }
  return null
}

// Get active sessions for current user
router.get('/',
  logUserActivity('view_sessions'),
  asyncHandler(async (req: AuthenticatedRequest, res) => {
    const userId = req.user?.id

    if (!userId) {
      return res.status(401).json({
        success: false,
        message: 'Authentication required'
      })
    }

    try {
      const { data: sessions, error } = await supabase
        .from('user_sessions')
        .select('id, device_info, location_info, created_at, last_activity, is_active')
        .eq('user_id', userId)
        .eq('is_active', true)
        .order('last_activity', { ascending: false })

      if (error) {
        logger.error('Get sessions failed', { error: error.message, userId })
        throw createError('Failed to fetch sessions: ' + error.message, 500)
      }

      // Process sessions to add user-friendly information
      const processedSessions = (sessions || []).map(session => {
        const deviceInfo = session.device_info || {}
        const locationInfo = session.location_info || {}

        return {
          id: session.id,
          device: {
            type: deviceInfo.device_type || 'unknown',
            browser: deviceInfo.browser || 'Unknown Browser',
            os: deviceInfo.operating_system || 'Unknown OS'
          },
          location: {
            country: locationInfo.country || 'Unknown',
            region: locationInfo.region || 'Unknown',
            city: locationInfo.city || 'Unknown'
          },
          created_at: session.created_at,
          last_activity: session.last_activity,
          is_current: false // This would be determined by comparing with current session
        }
      })

      res.json({
        success: true,
        sessions: processedSessions,
        total_count: processedSessions.length
      })

    } catch (error) {
      logger.error('Get sessions error', { 
        error: error instanceof Error ? error.message : String(error), 
        userId 
      })
      throw error
    }
  })
)

// Revoke specific session
router.delete('/:sessionId',
  logUserActivity('revoke_session'),
  asyncHandler(async (req: AuthenticatedRequest, res) => {
    const userId = req.user?.id
    const sessionId = req.params.sessionId

    if (!userId) {
      return res.status(401).json({
        success: false,
        message: 'Authentication required'
      })
    }

    try {
      // Verify session belongs to user
      const { data: session, error: fetchError } = await supabase
        .from('user_sessions')
        .select('id')
        .eq('id', sessionId)
        .eq('user_id', userId)
        .single()

      if (fetchError || !session) {
        return res.status(404).json({
          success: false,
          message: 'Session not found'
        })
      }

      // Deactivate session
      const { error } = await supabase
        .from('user_sessions')
        .update({ 
          is_active: false,
          updated_at: new Date().toISOString()
        })
        .eq('id', sessionId)
        .eq('user_id', userId)

      if (error) {
        logger.error('Session revocation failed', { error: error.message, userId, sessionId })
        throw createError('Failed to revoke session: ' + error.message, 400)
      }

      logger.info('Session revoked', { userId, sessionId })

      res.json({
        success: true,
        message: 'Session revoked successfully'
      })

    } catch (error) {
      logger.error('Revoke session error', { 
        error: error instanceof Error ? error.message : String(error), 
        userId,
        sessionId 
      })
      throw error
    }
  })
)

// Revoke all sessions except current
router.delete('/all/others',
  logUserActivity('revoke_all_other_sessions'),
  asyncHandler(async (req: AuthenticatedRequest, res) => {
    const userId = req.user?.id
    const currentSessionToken = req.headers.authorization?.substring(7) // Remove "Bearer "

    if (!userId) {
      return res.status(401).json({
        success: false,
        message: 'Authentication required'
      })
    }

    try {
      // Get current session ID if available
      let currentSessionId = null
      if (currentSessionToken) {
        const { data: currentSession } = await supabase
          .from('user_sessions')
          .select('id')
          .eq('session_token', currentSessionToken)
          .eq('user_id', userId)
          .single()
        
        currentSessionId = currentSession?.id
      }

      // Deactivate all sessions except current
      let query = supabase
        .from('user_sessions')
        .update({ 
          is_active: false,
          updated_at: new Date().toISOString()
        })
        .eq('user_id', userId)

      if (currentSessionId) {
        query = query.neq('id', currentSessionId)
      }

      const { data: updatedSessions, error } = await query.select('id')

      if (error) {
        logger.error('Bulk session revocation failed', { error: error.message, userId })
        throw createError('Failed to revoke sessions: ' + error.message, 400)
      }

      const revokedCount = updatedSessions?.length || 0

      logger.info('Multiple sessions revoked', { userId, revokedCount })

      res.json({
        success: true,
        message: `${revokedCount} sessions revoked successfully`,
        revoked_count: revokedCount
      })

    } catch (error) {
      logger.error('Revoke all sessions error', { 
        error: error instanceof Error ? error.message : String(error), 
        userId 
      })
      throw error
    }
  })
)

// Create new session (for remember me functionality)
router.post('/',
  [
    body('device_info').optional().isObject(),
    body('remember_me').optional().isBoolean()
  ],
  logUserActivity('create_session'),
  asyncHandler(async (req: AuthenticatedRequest, res) => {
    const validationError = checkValidation(req, res)
    if (validationError) return validationError

    const userId = req.user?.id
    const { device_info, remember_me = false } = req.body
    const userAgent = req.get('User-Agent')
    const ipAddress = req.ip

    if (!userId) {
      return res.status(401).json({
        success: false,
        message: 'Authentication required'
      })
    }

    try {
      // Generate session token
      const sessionToken = crypto.randomUUID()
      
      // Determine expiration time
      const expiresAt = new Date()
      expiresAt.setDate(expiresAt.getDate() + (remember_me ? 30 : 1)) // 30 days for remember me, 1 day otherwise

      const sessionData = {
        user_id: userId,
        session_token: sessionToken,
        device_info: {
          user_agent: userAgent,
          device_type: /Mobile/.test(userAgent || '') ? 'mobile' : 'desktop',
          browser: extractBrowser(userAgent),
          operating_system: extractOS(userAgent),
          ...device_info
        },
        location_info: {
          ip_address: ipAddress,
          // In a real implementation, you would use a GeoIP service
          country: 'Unknown',
          region: 'Unknown',
          city: 'Unknown'
        },
        created_at: new Date().toISOString(),
        expires_at: expiresAt.toISOString(),
        last_activity: new Date().toISOString(),
        is_active: true
      }

      const { data: session, error } = await supabase
        .from('user_sessions')
        .insert(sessionData)
        .select('id, created_at, expires_at')
        .single()

      if (error) {
        logger.error('Session creation failed', { error: error.message, userId })
        throw createError('Failed to create session: ' + error.message, 400)
      }

      logger.info('Session created', { 
        userId, 
        sessionId: session.id,
        rememberMe: remember_me,
        deviceType: sessionData.device_info.device_type
      })

      res.json({
        success: true,
        message: 'Session created successfully',
        session: {
          id: session.id,
          token: sessionToken,
          expires_at: session.expires_at,
          created_at: session.created_at
        }
      })

    } catch (error) {
      logger.error('Create session error', { 
        error: error instanceof Error ? error.message : String(error), 
        userId 
      })
      throw error
    }
  })
)

// Update session activity
router.put('/activity',
  asyncHandler(async (req: AuthenticatedRequest, res) => {
    const userId = req.user?.id
    const currentSessionToken = req.headers.authorization?.substring(7)

    if (!userId || !currentSessionToken) {
      return res.status(401).json({
        success: false,
        message: 'Authentication required'
      })
    }

    try {
      const { error } = await supabase
        .from('user_sessions')
        .update({ 
          last_activity: new Date().toISOString()
        })
        .eq('session_token', currentSessionToken)
        .eq('user_id', userId)
        .eq('is_active', true)

      if (error) {
        logger.error('Session activity update failed', { error: error.message, userId })
        // Don't throw error for activity updates, just log it
      }

      res.json({
        success: true,
        message: 'Session activity updated'
      })

    } catch (error) {
      logger.error('Update session activity error', { 
        error: error instanceof Error ? error.message : String(error), 
        userId 
      })
      // Return success even if update fails
      res.json({
        success: true,
        message: 'Session activity update attempted'
      })
    }
  })
)

// Clean up expired sessions (internal endpoint)
router.delete('/cleanup',
  asyncHandler(async (req, res) => {
    try {
      const { data: expiredSessions, error } = await supabase
        .from('user_sessions')
        .delete()
        .lt('expires_at', new Date().toISOString())
        .select('id')

      if (error) {
        logger.error('Session cleanup failed', { error: error.message })
        throw createError('Failed to cleanup sessions: ' + error.message, 500)
      }

      const cleanedCount = expiredSessions?.length || 0

      logger.info('Expired sessions cleaned up', { cleanedCount })

      res.json({
        success: true,
        message: `${cleanedCount} expired sessions cleaned up`,
        cleaned_count: cleanedCount
      })

    } catch (error) {
      logger.error('Session cleanup error', { 
        error: error instanceof Error ? error.message : String(error)
      })
      throw error
    }
  })
)

// Helper functions
function extractBrowser(userAgent?: string): string {
  if (!userAgent) return 'Unknown'
  
  if (userAgent.includes('Chrome')) return 'Chrome'
  if (userAgent.includes('Firefox')) return 'Firefox'
  if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) return 'Safari'
  if (userAgent.includes('Edge')) return 'Edge'
  if (userAgent.includes('Opera')) return 'Opera'
  
  return 'Unknown'
}

function extractOS(userAgent?: string): string {
  if (!userAgent) return 'Unknown'
  
  if (userAgent.includes('Windows')) return 'Windows'
  if (userAgent.includes('Mac OS')) return 'macOS'
  if (userAgent.includes('Linux')) return 'Linux'
  if (userAgent.includes('Android')) return 'Android'
  if (userAgent.includes('iOS')) return 'iOS'
  
  return 'Unknown'
}

export default router